char buffer[32];
char signal[122];

void setup()
{
  Serial.begin( 19200 );
  Serial.flush();
  
  Serial.println( "Ready");
  
  pinMode( 12, OUTPUT );
}
 
void loop()
{
  if (Serial.available() > 0) {
    readLine( buffer, 100 );
    if( strcmp( buffer, "on" ) == 0 ) 
    {
      Serial.println("light on");
      createSignal( signal, 0, 193 );
      sendSignal( signal, 12 );
    }
    else if( strcmp( buffer, "off" ) == 0 )
    {
      Serial.println("light off");
      createSignal( signal, 0, 65 );
      sendSignal( signal, 12 );
    }
    else if( strncmp( buffer, "cmd", 3 ) == 0 )
    {
      createSignal( signal, 0, atoi( buffer + 3 ) );
      sendSignal( signal, 12 );
      Serial.println(buffer);
    }
    else
    {
      Serial.print("Unknown command: ");
      Serial.println( buffer );
    }
  }
}

void readLine( char * buffer, int timeOut )
{
  while( true )
  {
    if( Serial.available() > 0 )
    {
      *buffer = Serial.read();
      if( *buffer == '\0' )
      {
        *buffer = '\0';
        return;
      }
      buffer++;
    }
  }
}

void toNECBits( char * out, char in )
{
  for( int i = 0; i < 8; i++ )
  {
    if( (in << i & 128) != 0 )
    {
      *out = '1';
      out++;
      *out = '0';
      out++;
      *out = '0';
      out++;
      *out = '0';
      out++;
    }
    else
    {
      *out = '1';
      out++;
      *out = '0';
      out++;      
    }
  }
  *out = '\0';
}

void createSignal( char * signal, char address, char command )
{
  char bitString[33];
  char * pWorking = 0;

  // pointer to iterate over signalOut
  char * currentOut = signal;
  
  // 9ms leading pulse burst -> 16 regular bursts
  for( int i = 0; i < 16; i++ )
  {
      *currentOut = '1';
      currentOut++;    
  }
  
  // 4.5ms space 
  for( int i = 0; i < 8; i++ )
  {
      *currentOut = '0';
      currentOut++;    
  }
  
  
  toNECBits( bitString, address );
  pWorking = bitString;
  while( *pWorking != '\0' )
  {
    *currentOut = *pWorking;
    currentOut++;
    pWorking++;
  }
  
  toNECBits( bitString, ~address );
  pWorking = bitString;
  while( *pWorking != '\0' )
  {
    *currentOut = *pWorking;
    currentOut++;
    pWorking++;
  }
  
  
  toNECBits( bitString, command );
  pWorking = bitString;
  while( *pWorking != '\0' )
  {
    *currentOut = *pWorking;
    currentOut++;
    pWorking++;
  }
  
  toNECBits( bitString, ~command );
  pWorking = bitString;
  while( *pWorking != '\0' )
  {
    *currentOut = *pWorking;
    currentOut++;
    pWorking++;
  }
 
  // a final burst to signify the end of package
  *currentOut = '1';
  currentOut++;  
  
  *currentOut = '\0';
}

void sendSignal( char * signal, int pin )
{
  char * currentChar = signal;
  
  // iterate over the signal string
  while( *currentChar != 0 )
  {
    if( *currentChar == '0' )
    { 
      // 562.5µs low space
      digitalWrite( pin, LOW );
      delayMicroseconds( 552 );
    }
    else
    {
      // approx. 562.5µs 38kHz square wave
      for( int i = 0; i < 20; i++ )
      {
        digitalWrite( pin, HIGH );
        delayMicroseconds( 9 );
        digitalWrite( pin, LOW );
        delayMicroseconds( 10 );        
      }
    }
    currentChar++;
  }
}
